/*
	Copyright (c) 2009-2011, Stefan Webb.

	This file is part of SimpleML. Please read the file "license.txt", 
	which contains the conditions under which this software is distributed.
*/
/*!
	\file string.h
	\author Stefan Webb
	\brief Definition of the String class.
*/

#ifndef STRING_H
#define STRING_H

//#include "stdafx.h"

/*! \brief Class to use stack. */
template <class T = utf16> class String : protected Bucket<T>
{
public:
	/*! \brief Default constructor. */
	String(void);

	/*! \brief Constructor with initial capacity.
		\param capacity Initial capacity of string. */
	String(unsigned int capacity);

	/*! \brief Constructor with specified string. 
		\param string Contents for new string. Object will delete [] this 
		string on destruction. */
	String(T* string);

	/*! \brief Append characters to this string.
		\param string Characters to append. */
	void append(char* string);

	/*! \brief Append ASCII characters to this string.
		\param string Characters to append. */
	void append(utf16* string);

	/*! \brief Append n characters to this string.
		\param string Characters to append.
		\param length Length of this string. */
	void append(T* string, unsigned int length);

	/*! \brief Determine size of string.
		\return Size of string. */
	unsigned int size();

	/*! \brief Determine capacity of string.
		\return Capacity of string. */
	unsigned int capacity();

	/*! \brief Create empty string with specified capacity.
		\param capacity Capacity of new string. */
	void create(unsigned int capacity);

	/*! \brief Create string with specified contents.
		\param string Contents for new string. Object will delete [] this 
		string on destruction. */
	void create(T* string);

	/*! \brief Create string with specified contents and length.
		\param string Contents for new string. Object will delete [] this 
		string on destruction.
		\param length Length of string specified by param 'string'. */
	void create(T* string, unsigned int length);

	/*! \brief Free memory associated with string. */
	void destroy(void);

	/*! \brief Return pointer to string. */
	T* string(void);

	/*! \brief Get string element, without bounds check (for speed).
		\param i Index of element to retrieve.
		\return Element at specified index. */
	T& operator[](unsigned int i);

	/*! \brief Expand string size to its capacity. */
	void expand();
};

/* Default constructor. */
template <class T> String<T>::String(void) : Bucket() {}

/* Constructor with initial capacity. */
template <class T> String<T>::String(unsigned int capacity) : Bucket(capacity)
{
	// Make sure the string is terminated. // *** NEED TO DO SOMETHING HERE ***
	T terminator = 0;
	push(terminator);
	size_--;
}

/* Constructor with specified string. */
template <class T> String<T>::String(T* string)
{
	initialize();
	create(string);
}

/* Append characters to this string. */
template <class T> void String<T>::append(utf16* string)
{
	// While we haven't yet reached null termination...
	do {
		// Double stack if we do not have enough capacity
		if (size_ >= capacity_)
			twofold();

		// Add element
		(*this)[size_++] = (T) *string;
	} while (*string++ != (T) 0);

	// Decrement size by one so we overwrite null terminator next time
	size_--;
}

/* Append ASCII characters to this string. */
template <class T>
void String<T>::append(char* string)
{
	// While we haven't yet reached null termination...
	do {
		// Double stack if we do not have enough capacity
		if (size_ >= capacity_)
			twofold();

		// Add element
		(*this)[size_++] = (T) *string;
	} while (*string++ != (T) 0);

	// Decrement size by one so we overwrite null terminator next time
	size_--;
}

/* Append n characters to this string. */
template <class T>
void String<T>::append(T* string, unsigned int length)
{
	// While we haven't yet reached null termination...
	do {
		// Double stack if we do not have enough capacity
		if (size_ >= capacity_)
			twofold();

		// Add element
		(*this)[size_++] = *string++;
	} while (--length);

	// Fill in zero terminator
	if (size_ >= capacity_)
		twofold();
	(*this)[size_] = 0;
}

/* Determine size of string. */
template <class T> unsigned int String<T>::size()
{
	return Bucket::size();
}

/* Determine capacity of string. */
template <class T> unsigned int String<T>::capacity()
{
	return Bucket::capacity();
}

/* Create empty string with specified capacity. */
template <class T> void String<T>::create(unsigned int capacity)
{
	Bucket::create(capacity + 1);
}

/* Create string with specified contents. */
template <class T> void String<T>::create(T* string)
{
	create(string, wcslen(string));
}

/* Create string with specified contents and length. */
template <class T> void String<T>::create(T* string, unsigned int length)
{
	// Delete string if required
	if (array_)
		delete [] array_;

	// Get memory for bucket items
	array_ = string;

	// Set capacity and size
	capacity_ = length + 1;
	initialCapacity_ = capacity_;
	minimumCapacity_ = capacity_;
	size_ = capacity_ - 1;
}

/* Free memory associated with string. */
template <class T> void String<T>::destroy(void)
{
	Bucket::destroy();
}

/* Return pointer to string. */
template <class T> T* String<T>::string(void)
{
	return array_;
}

/* Get string element, without bounds check (for speed). */
template <class T> T& String<T>::operator[](unsigned int i)
{
	return Bucket::operator[](i);
}

/* Expand string size to its capacity. */
template <class T> void String<T>::expand()
{
	// Expand bucket and fill in zero terminator
	Bucket::expand();
	array_[size_ - 1] = 0;
	size_--;
}

#endif
